﻿//Copyright (c) 2010, Andreas Grünwald
//All rights reserved.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using yaTDL.Core.Properties;
using yaTDL.Extensions;
using System.Reflection;
using System.Diagnostics;
using System.Threading;

namespace yaTDL.Core.MVVM
{
    /// <summary>
    /// ViewModel for the Settings-UI
    /// </summary>
    public class SettingsViewModel:ViewModelBase
    {
        #region Fields

        RelayCommand _okCommand;
        RelayCommand _cancelCommand;
        RelayCommand _editAccountCommand;
        RelayCommand _deleteAccountCommand;
        RelayCommand _createBackupCommand;
        RelayCommand _startSyncCommand;
        RelayCommand _openHyperlinkCommand;
        RelayCommand _resetSyncDataCommand;

        string _editAccountButtonText;
        string _accountInfoText;

        LoginViewModel loginViewModel;

        ApplicationSettings _settings = ApplicationSettings.Settings;

        bool reactOnSettingsPropertyChanged = true;

        #endregion

        #region Properties

        /// <summary>
        /// Saves all changes made to the settings and closes the View
        /// </summary>
        public ICommand OkCommand
        {
            get
            {
                if (_okCommand == null)
                {
                    _okCommand = new RelayCommand(p => this.okCommandExecute(p));
                }
                return _okCommand;
            }
        }

        /// <summary>
        /// Closes the View without saving changes made to the settings
        /// </summary>
        public ICommand CancelCommand
        {
            get
            {
                if (_cancelCommand == null)
                {
                    _cancelCommand = new RelayCommand(p => this.cancelCommandExecute(p));
                }
                return _cancelCommand;
            }
        }

        /// <summary>
        /// Displays the View used to edit the currently used Toodledo-Account
        /// </summary>
        public ICommand EditAccountCommand
        {
            get
            {
                if (_editAccountCommand == null)
                {
                    _editAccountCommand = new RelayCommand(p => this.editAccountCommandExecute(p));
                }
                return _editAccountCommand;
            }
        }

        /// <summary>
        /// Deletes all Toodledo account information
        /// </summary>
        public ICommand DeleteAccountCommand
        {
            get
            {
                if (_deleteAccountCommand == null)
                {
                    _deleteAccountCommand = new RelayCommand(p => this.deleteAccountCommandExecute(p), p => this.deleteAccountCommandCanExecute(p));
                }
                return _deleteAccountCommand;
            }
        }

        /// <summary>
        /// Creates a new Backup. See <see cref="TaskStore.Backup()"/>
        /// </summary>
        public ICommand CreateBackupCommand
        {
            get
            {
                if (_createBackupCommand == null)
                {
                    _createBackupCommand = new RelayCommand(p => this.createBackupCommandExecute(p), p => this.createBackupCommandCanExecute(p));
                }
                return _createBackupCommand;
            }
        }

        /// <summary>
        /// Manually starts a synchronisation with Toodledo
        /// </summary>
        public ICommand StartSyncCommand
        {
            get
            {
                if (_startSyncCommand == null)
                {
                    _startSyncCommand = new RelayCommand(p => this.startSyncCommandExecute(p), p => this.startSyncCommandCanExecute(p));
                }
                return _startSyncCommand;
            }
        }

        /// <summary>
        /// Opens the url defined in the Command's CommandParameter
        /// </summary>
        public ICommand OpenHyperlinkCommand
        {
            get
            {
                if (_openHyperlinkCommand == null)
                {
                    _openHyperlinkCommand = new RelayCommand(p => this.openHyperlinkCommandExecute(p));
                }
                return _openHyperlinkCommand;
            }
        }

        /// <summary>
        /// Resets emporary data stored about sync with Toodledo (APIKey and time of last sync)
        /// </summary>
        public ICommand ResetSyncDataCommand
        {
            get
            {
                if (_resetSyncDataCommand == null)
                {
                    _resetSyncDataCommand = new RelayCommand(p => this.resetSyncDataCommandExecute(p), p => this.resetSyncDataCommandCanExecute(p));
                }
                return _resetSyncDataCommand;
            }
        }

        /// <summary>        
        /// The text to be displayed on the button that is bound to <see cref="EditAccountCommand"/>
        /// </summary>
        public string EditAccountButtonText
        {
            get { return _editAccountButtonText; }
            set
            {
                if (value != _editAccountButtonText)
                {
                    _editAccountButtonText = value;
                    RaisePropertyChanged("EditAccountButtonText");
                }
            }
        }

        /// <summary>
        /// The text describing the information stored about the currently used Toodledo-Account
        /// </summary>
        public string AccountInfoText
        {
            get { return _accountInfoText; }
            set
            {
                if (value != _accountInfoText)
                {
                    _accountInfoText = value;
                    RaisePropertyChanged("AccountInfoText");
                }
            }
        }

        /// <summary>
        /// The Version String of yaTDL.Core
        /// </summary>
        public string ApplicationVersion
        {
            get 
            {
                string ver = Assembly.GetExecutingAssembly().FullName.Split(',')[1].Substring(9);            
#if DEBUG
                ver += " (Debug)";                
#endif
                return ver;
            }
        }

        /// <summary>
        /// A reference to the currenlty used ApplicationSettings class.
        /// </summary>
        public ApplicationSettings Settings
        {
            get { return _settings; }
        }

        #endregion


        #region Constructos and private methods

        /// <summary>
        /// Initializes a new instce of SettingsViewModel
        /// </summary>
        public SettingsViewModel()
        {
            Settings.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(Settings_PropertyChanged);

            setAccountInfo(null);
        }

        void Settings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (reactOnSettingsPropertyChanged)
            {
                switch (e.PropertyName)
                {
                    case "Toodledo_UserId":
                        setAccountInfo(null);
                        break;
                }
            }
        }
        

        private void setAccountInfo(object parameter)
        {
            if (parameter is LoginViewModel)            
            {
                reactOnSettingsPropertyChanged = false;
                LoginViewModel viewModel = parameter as LoginViewModel;
                Settings.Toodledo_Password = viewModel.Password;
                Settings.Toodledo_UserId = viewModel.UserId.ToSecureString();
                reactOnSettingsPropertyChanged = true;                       
            }

            if (!Settings.Toodledo_UserId.IsNullOrEmpty())
            {
                AccountInfoText = String.Format("Account set, UserId: {0}", Settings.Toodledo_UserId.Unwrap());
                EditAccountButtonText = "Edit Account";
            }
            else
            {
                AccountInfoText = "No Account set";
                EditAccountButtonText = "Add Account";
            }
        }

        #endregion


        #region Command Methods

        /// <summary>
        /// Execution-logic of  <see cref="OkCommand"/>
        /// </summary>
        /// <param name="parameter">The CommandParameter of the Command (currently unused, can be null)</param>
        private void okCommandExecute(object parameter)
        {
            Settings.Save();            

            this.CloseView();
        }

        /// <summary>
        /// Execution-logic of  <see cref="CancelCommand"/>
        /// </summary>
        /// <param name="parameter">The CommandParameter of the Command (currently unused, can be null)</param>
        private void cancelCommandExecute(object parameter)
        {
            //reload settings, but save time of last backup and last sync
            Settings.ReloadAllBut("Backup_LastBackup", "Toodledo_LastSync");
            Settings.Save();
            
            this.CloseView();
        }

        /// <summary>
        /// Execution-logic of  <see cref="EditAccountCommand"/>
        /// </summary>
        /// <param name="parameter">The CommandParameter of the Command (currently unused, can be null)</param>
        private void editAccountCommandExecute(object parameter)
        {
            loginViewModel = new LoginViewModel(Settings.Toodledo_UserId.Unwrap(), Settings.Toodledo_Password);
            ViewManager.ShowView(loginViewModel, p => this.setAccountInfo(p)); 
        }

        /// <summary>
        /// Checks whether  <see cref="DeleteAccountCommand"/> can currently be executed.
        /// </summary>
        /// <param name="parameter">The CommandParameter of the Command (currently unused, can be null)</param>
        private bool deleteAccountCommandCanExecute(object parameter)
        {
            return Settings.Toodledo_UserId.IsNullOrEmpty() ? false : true;                       
        }

        /// <summary>
        /// Execution-logic of  <see cref="DeleteAccountCommand"/>
        /// </summary>
        /// <param name="parameter">The CommandParameter of the Command (currently unused, can be null)</param>
        private void deleteAccountCommandExecute(object parameter)
        {
            Settings.Reset("Toodledo_UserId", "Toodledo_Password");            
            setAccountInfo(null);
        }


        /// <summary>
        /// Checks whether  <see cref="CreateBackupCommand"/> can currently be executed.
        /// </summary>
        /// <param name="parameter">The CommandParameter of the Command (currently unused, can be null)</param>
        private bool createBackupCommandCanExecute(object parameter)
        {
            return Settings.Backup_Enable;
        }


        /// <summary>
        /// Execution-logic of  <see cref="CreateBackupCommand"/>
        /// </summary>
        /// <param name="parameter">The CommandParameter of the Command (currently unused, can be null)</param>
        private void createBackupCommandExecute(object parameter)
        {            
            TaskStore.Backup();
        }

        /// <summary>
        /// Checks whether  <see cref="StartSyncCommand"/> can currently be executed.
        /// </summary>
        /// <param name="parameter">The CommandParameter of the Command (currently unused, can be null)</param>
        private bool startSyncCommandCanExecute(object parameter)
        {
            return Settings.Toodledo_EnableSync;
        }

        /// <summary>
        /// Execution-logic of  <see cref="StartSyncCommand"/>
        /// </summary>
        /// <param name="parameter">The CommandParameter of the Command (currently unused, can be null)</param>
        private void startSyncCommandExecute(object parameter)
        {
            new Thread(TaskStore.SyncService.Run).Start();
        }

      
        /// <summary>
        /// Execution-logic of  <see cref="OpenHyperlinkCommand"/>
        /// </summary>
        /// <param name="parameter">The Hyperlink's target url</param>
        private void openHyperlinkCommandExecute(object parameter)
        {
            Process.Start(parameter as string);

        }

        /// <summary>
        /// Checks whether  <see cref="ResetSyncDataCommand"/> can currently be executed.
        /// </summary>
        /// <param name="parameter">The CommandParameter of the Command (currently unused, can be null)</param>
        private bool resetSyncDataCommandCanExecute(object parameter = null)
        {
            if (!String.IsNullOrEmpty(Settings.Toodledo_APIKey.Key) || Settings.Toodledo_LastSync.Date != DateTime.Parse("01.01.0001"))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Execution-logic of <see cref="ResetSyncDataCommand"/>
        /// </summary>
        /// <param name="parameter">The CommandParameter of the Command (currently unused, can be null)</param>
        private void resetSyncDataCommandExecute(object parameter = null)
        {
            Settings.Reset("Toodledo_LastSync", "Toodledo_APIKey");
            Settings.Save("Toodledo_LastSync", "Toodledo_APIKey");
        }

        #endregion
    }
}
